home *** CD-ROM | disk | FTP | other *** search
/ Mac Cube 4: Multimedia Applications / MacCube Volume 4: Multimedia Applications.iso / Graphics / POV Ray / POVSOURCE / SOURCE / Printf2Window.c < prev    next >
Text File  |  1994-02-04  |  57KB  |  1,726 lines

  1. /*
  2. ==============================================================================
  3. Project:    POV-Ray
  4.  
  5. Version:    2.2
  6.  
  7. File Name:    Printf2Window.c
  8.  
  9. Description:
  10.     General-purpose printf-capturing routines that allow a console-like
  11.     output window for c programs that otherwise prefer to use printf/fprintf.
  12.     This code was "inspired heavily" from sources such as MacDTS'es TESample,
  13.     MacApp's Transcript window, and previous code of mine.  It is fairly well
  14.     self-contained, and works in MPW C 3.2 and Think C 5.0.
  15.  
  16.     This is the main source file, containing the private definitions and
  17.     code to implement all the needed external and internal support functions.
  18.  
  19. Related Files:
  20.     Stdio_p2w.h        - generic header for sources that would otherwise use <stdio.h>
  21.     Printf2Window.h    - Mac-specific header for p2w routines
  22.     Printf2Window.c    - the main source for the p2w routines
  23. ------------------------------------------------------------------------------
  24. Author:
  25.     Eduard [esp] Schwan
  26. ------------------------------------------------------------------------------
  27.     from Persistence of Vision Raytracer
  28.     Copyright 1993 Persistence of Vision Team
  29. ------------------------------------------------------------------------------
  30.     NOTICE: This source code file is provided so that users may experiment
  31.     with enhancements to POV-Ray and to port the software to platforms other 
  32.     than those supported by the POV-Ray Team.  There are strict rules under
  33.     which you are permitted to use this file.  The rules are in the file
  34.     named POVLEGAL.DOC which should be distributed with this file. If 
  35.     POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  36.     Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  37.     Forum.  The latest version of POV-Ray may be found there as well.
  38.  
  39.     This program is based on the popular DKB raytracer version 2.12.
  40.     DKBTrace was originally written by David K. Buck.
  41.     DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  42. ------------------------------------------------------------------------------
  43. More Info:
  44.     This Macintosh version of POV-Ray was created and compiled by Jim Nitchals
  45.     (Think 5.0) and Eduard Schwan (MPW 3.2), based (loosely) on the original
  46.     port by Thomas Okken and David Lichtman, with some help from Glenn Sugden.
  47.  
  48.     For bug reports regarding the Macintosh version, you should contact:
  49.     Eduard [esp] Schwan
  50.         CompuServe: 71513,2161
  51.         Internet: jl.tech@applelink.apple.com
  52.         AppleLink: jl.tech
  53.     Jim Nitchals
  54.         Compuserve: 73117,3020
  55.         America Online: JIMN8
  56.         Internet: jimn8@aol.com -or- jimn8@applelink.apple.com
  57.         AppleLink: JIMN8
  58. ------------------------------------------------------------------------------
  59. Change History:
  60.     920318    [esp]    Created.
  61.     920325    [esp]    Added init/Terminate, major redesign of std c fns.
  62.     920327    [esp]    Robustized AddCString code that handles TERec-is-full delete logic
  63.     920329    [esp]    Added AdjustScrollBars call in AddCString to update scrollers as text is added
  64.     920330    [esp]    Updated file header with copyright & related files info
  65.     920401    [esp]    Added p2wSignature to window record for safety checking
  66.     920402    [esp]    Fixed cr/lf bug in bottleneck routine
  67.     920412    [esp]    Fixed potential integer overflow in comparison in AddCString routine
  68.     920412    [esp]    Added most function header comments, added windBounds support in Newp2wWindow, fixed scroller activate bug
  69.     920413    [esp]    Fixed misbehavin' scrollbars hilite upon activate/deactivate
  70.     920521    [esp]    Made the non-resource based code work.
  71.     920529    [esp]    Changed type defs to have trailing _t for ANSI consistency
  72.     920529    [esp]    Added p2w_SetTextFont function to allow easy fontsize switching
  73.     920603    [esp]    Initialized newly alloc'ed ctrls to VISIBLE
  74.     920816    [esp]    Added p2w_SelectAll routine
  75.     920901    [esp]    reduced kMaxTELength to 32000 so TeachText doesn't choke on >32000 sized files!
  76.     920905    [esp]    Fixed scrollbars so they're inactive on window creation.
  77.     920912    [esp]    Added windID parm to NewWindow call
  78.     921011    [esp]    Updated bottleneck to handle fopen() file I/O too (pass-through)
  79.     921128    [esp]    Fixed bug in p2w_fputs: the newline went to stdout, not stream!
  80.     931001    [esp]    version 2.0 finished (Released on 10/4/93)
  81.     931119    [djh]    2.0.1 conditionally compiles for PPC machines, keyword __powerc
  82. ==============================================================================
  83. */
  84.  
  85. /* Standard C library headers */
  86. #include <stdarg.h>        // ANSI C variable length argument support
  87. #include <string.h>        // strlen
  88.  
  89. /* Macintosh-specific headers */
  90. #include <Types.h>
  91. #include <Controls.h>
  92. #include <Dialogs.h>
  93. #include <Files.h>
  94. #include <Memory.h>
  95. #include <OSUtils.h>
  96. #include <Resources.h>
  97. #include <Windows.h>
  98. #include <Scrap.h>
  99.  
  100. #if !defined(THINK_C)
  101. #include <strings.h>        /*p2cstr*/
  102. #endif // THINK_C
  103.  
  104. #include "screenUtils.h"    /* GetMaxGrowRect */
  105. #include "printf2window.h"    /* our defs AND stdio.h for sprintf, etc. */
  106.  
  107. #if defined(__powerc)
  108. extern QDGlobals qd;
  109. extern RoutineDescriptor gVScrollRD;
  110. extern RoutineDescriptor gHScrollRD;
  111. #endif
  112.  
  113. // ==== Constant definitions
  114.  
  115. // Comment USE_P2W_RESOURCES out to create the controls from scratch..
  116. // Leave it in to create them from resources
  117.  
  118. // #define    USE_P2W_RESOURCES    true
  119.  
  120.  
  121. // Resource IDs of supporting p2w resources
  122.  
  123. #if defined(USE_P2W_RESOURCES)
  124. #define    kp2w_VScrollID        9601
  125. #define    kp2w_HScrollID        9602
  126. #endif // USE_P2W_RESOURCES
  127.  
  128.  
  129. // Magic p2w window record signature value
  130.  
  131. #define    kp2wWindowSignature    'p2w '
  132.  
  133.  
  134. // kTextMargin is the number of pixels we leave blank at the edge of the window.
  135.  
  136. #define kTextMargin                2
  137.  
  138.  
  139. // kControlInvisible is used to 'turn off' controls (i.e., cause the control not
  140. // to be redrawn as a result of some Control Manager call such as SetCtlValue)
  141. // by being put into the contrlVis field of the record. kControlVisible is used
  142. // the same way to 'turn on' the control.
  143.  
  144. #define kControlInvisible        0
  145. #define kControlVisible            0xFF
  146.  
  147.  
  148. // kControlHiliteActive is used to activate controls (contrlHilite)
  149. // kControlHiliteInactive is used to deactivate controls (contrlHilite)
  150.  
  151. #define kControlHiliteActive        0
  152. #define kControlHiliteInactive        0xFF
  153.  
  154.  
  155. // kButtonScroll is how many pixels to scroll horizontally when the button part
  156. // of the horizontal scrollbar is pressed.
  157.  
  158. #define kButtonScroll            4
  159.  
  160. // kScrollbarAdjust and kScrollbarWidth are used in calculating
  161. // values for control positioning and sizing.
  162.  
  163. #define kScrollbarWidth            16
  164. #define kScrollbarAdjust        (kScrollbarWidth - 1)
  165.  
  166.  
  167. // kScrollTweek compensates for off-by-one requirements of the scrollbars
  168. // to have borders coincide with the growbox.
  169.  
  170. #define kScrollTweek            2
  171.  
  172.  
  173. // kMaxTELength is an arbitrary number used to limit the length of text in the TERec
  174. // so that various errors won't occur from too many characters in the text.  When the
  175. // string to be added exceeds kMaxTELength, then strlen+kTEDeleteChunkSize
  176. // characters will be deleted from the beginning of the TERec.  This lets the TE
  177. // buffer stay pretty full while characters "fall off the top" of the buffer, and
  178. // insures that the performance delay of deleting from the front of the buffer
  179. // only happens every once in awhile, instead of for every single additional
  180. // string added.  kTEDeleteChunkSize should probably be between 1k and 20k..
  181.  
  182. #define    kMaxTELength            32000    // 32000 is pretty close to 32767, OK TeachText?
  183. #define    kTEDeleteChunkSize        5000    // should be between 1000 and 20000
  184.  
  185.  
  186. // kMinDocSize is the smallest horiz/vert size of a grown window.
  187.  
  188. #define    kMinDocSize                100
  189.  
  190.  
  191. // kMaxStdIOBuffSize is the largest supported size of a single formatted
  192. // stdio C string.  Note that internally, a relocatable buffer of this size
  193. // will be allocated.
  194.  
  195. #define    kMaxStdIOBuffSize        1024
  196.  
  197.  
  198. // internal macro definitions
  199.  
  200. // Define some structure accessing macros for efficiency.
  201. #define GET_HIWORD(aLong)    (((aLong)>>16)&0x0FFFFL)
  202. #define GET_LOWORD(aLong)    ((aLong)&0x0FFFFL)
  203. #define GET_TOPLEFT_POINT(aRect)    (*(Point*)&(aRect).top)
  204. #define GET_BOTRIGHT_POINT(aRect)    (*(Point*)&(aRect).bottom)
  205. #define GET_RECT_WIDTH(aRect)        ((aRect).right - (aRect).left)
  206. #define GET_RECT_HEIGHT(aRect)        ((aRect).bottom - (aRect).top)
  207. #define IS_P2W_WINDOW(p2wPtr) (((p2w_WindowPtr_t)p2wPtr)->p2wSignature == kp2wWindowSignature)
  208.  
  209. /*
  210. ----------------------------------
  211. prototypes for internal routines
  212. ----------------------------------
  213. */
  214.  
  215. static void p2wi_GetTERect(const p2w_WindowPtr_t thep2wWindow, Rect *teRect);
  216. static void p2wi_AdjustTE(const p2w_WindowPtr_t thep2wWindow);
  217. static void p2wi_AdjustViewRect(TEHandle p2wTE);
  218. static void p2wi_CommonAdjustScroller(const Boolean isVert, const p2w_WindowPtr_t thep2wWindow, ControlHandle control, TEHandle theTEHandle, const Boolean canRedraw);
  219. static void p2wi_AdjustScrollValues(const p2w_WindowPtr_t thep2wWindow, const Boolean doRedraw);
  220. static void p2wi_AdjustScrollSizes(const p2w_WindowPtr_t thep2wWindow);
  221. static void p2wi_AdjustScrollbars(const p2w_WindowPtr_t thep2wWindow, const Boolean doResize);
  222. static void p2wi_ResizeWindow(const p2w_WindowPtr_t thep2wWindow);
  223. static void p2wi_GetLocalUpdateRegion(const p2w_WindowPtr_t thep2wWindow, RgnHandle localRgn);
  224. static void p2wi_CommonScrollAction(ControlHandle control, short *amount);
  225. pascal void p2wi_VScrollActionProc(ControlHandle control, short part);
  226. pascal void p2wi_HScrollActionProc(ControlHandle control, short part);
  227. static int p2wi_StdCOut_BottleNeck(FILE *stream);
  228. static int p2wi_vfprintf(FILE *stream, const char *format, va_list va_args);
  229.  
  230.  
  231.  
  232. /*
  233. ----------------------------------
  234. global variable definitions
  235. ----------------------------------
  236. */
  237.  
  238. static Handle            p2w_Stdio_OutBuf_Hdl = NULL;
  239. static p2w_WindowPtr_t    local_p2wWindow = NULL;
  240.  
  241.  
  242.  
  243. /*---------------------------------------------------------------------*/
  244. /*==== Main interface routines ====*/
  245.  
  246.  
  247. /*
  248. ******************************************************************************
  249. Name:
  250.     p2w_Init
  251. ------------------------------------------------------------------------------
  252. Purpose:
  253.     Primary (one-time) initialization of the p2w routines
  254. ------------------------------------------------------------------------------
  255. Description:
  256.     pre-allocates internal storage & initializes variables
  257. ------------------------------------------------------------------------------
  258. Parameters:
  259.     void
  260. ------------------------------------------------------------------------------
  261. When Used:
  262.     Called once, when the application starts up
  263. ******************************************************************************
  264. */
  265. OSErr p2w_Init(void)
  266. {
  267.     OSErr    anError = noErr;
  268.  
  269.     // allocate an output character stream buffer to use
  270.     p2w_Stdio_OutBuf_Hdl = NewHandle(kMaxStdIOBuffSize);
  271.     anError = MemError();
  272.     local_p2wWindow = NULL;
  273.  
  274.     return anError;
  275. } // p2w_Init
  276.  
  277.  
  278.  
  279. /*
  280. ******************************************************************************
  281. Name:
  282.     p2w_Terminate
  283. ------------------------------------------------------------------------------
  284. Purpose:
  285.     Primary (one-time) destruction of the p2w routines
  286. ------------------------------------------------------------------------------
  287. Description:
  288.     de-allocates internal storage & invalidates variables
  289. ------------------------------------------------------------------------------
  290. Parameters:
  291.     void
  292. ------------------------------------------------------------------------------
  293. When Used:
  294.     Called once, when the application is shutting down
  295. ******************************************************************************
  296. */
  297. OSErr p2w_Terminate(void)
  298. {
  299.     OSErr    anError = noErr;
  300.  
  301.     if (p2w_Stdio_OutBuf_Hdl)
  302.     {
  303.         DisposeHandle(p2w_Stdio_OutBuf_Hdl);
  304.         anError = MemError();
  305.     }
  306.     p2w_Stdio_OutBuf_Hdl = NULL;
  307.     local_p2wWindow = NULL;
  308.  
  309.     return anError;
  310. } // p2w_Terminate
  311.  
  312.  
  313.  
  314. /*
  315. ******************************************************************************
  316. Name:
  317.     p2w_NewWindow
  318. ------------------------------------------------------------------------------
  319. Purpose:
  320.     Creates a new p2w window structure for use by other p2w routines.
  321. ------------------------------------------------------------------------------
  322. Description:
  323.     Creates a p2w window (either from resources or from parameters),
  324.     initializes it, and shows it if asked.
  325. ------------------------------------------------------------------------------
  326. Parameters:
  327.     windID            if 0, create window from scratch, if > 0, use as ID for GetNewWindow
  328.     windBoundsPtr    Where to place the new window on the screen.
  329.                     If NULL, the resource bounds will be used.
  330.     windTitle        The Pascal title string to use for the new window.
  331.                     If NULL, resource title will be used.
  332.     windIsVisible    TRUE will show window after creation, FALSE will leave hidden.
  333.     windFont        Text Font to use for new window.
  334.     windFontSize    Text Font Size tose for new window.
  335.     anError            Returns any error code, or zero (noErr) if all went OK.
  336. ------------------------------------------------------------------------------
  337. When Used:
  338.     Called when a new p2w window needs to be allocated.  It may or may not
  339.     be shown at this time.  It will be opened in the back.  This call mainly 
  340.     creates the window structures.
  341. ******************************************************************************
  342. */
  343. p2w_WindowPtr_t p2w_NewWindow(    const    short        windID,
  344.                                 const    Rect        *windBoundsPtr,
  345.                                 const    Str255        windTitle,
  346.                                 const    Boolean        windIsVisible,
  347.                                 const    int            windFont,
  348.                                 const    short        windFontSize,
  349.                                         OSErr        *anError)
  350. {
  351.     WindowPtr        aWindow;
  352.     Rect            destRect, viewRect, screenRect;
  353.     p2w_WindowPtr_t    p2wWPtr = NULL;
  354.     GrafPtr            savedPort;
  355.  
  356.     GetPort(&savedPort);    // I'll be back..
  357.  
  358.     /* how big is the screen */
  359.     screenRect = qd.screenBits.bounds;
  360.  
  361.     /* allocate space for our extended p2window record */
  362.     p2wWPtr = (p2w_WindowPtr_t)NewPtr(sizeof(p2w_WindowRecord_t));
  363.     *anError = MemError();
  364.     if (!*anError)
  365.     {
  366.         // initialize the p2w record
  367.  
  368.         p2wWPtr->p2wSignature        = kp2wWindowSignature; // bless this special window record
  369.         p2wWPtr->p2wOpenedOK        = false; // until actually opened later
  370.         p2wWPtr->p2wTEHandle        = NULL;
  371.         p2wWPtr->p2wVScroller        = NULL;
  372.         p2wWPtr->p2wHScroller        = NULL;
  373.         p2wWPtr->p2wClickHandler    = NULL;
  374.         p2wWPtr->p2wMaxDocWidth        = GET_RECT_WIDTH(screenRect) - kScrollbarWidth - 2*kTextMargin - 10;
  375.         p2wWPtr->p2wAlwaysScrollToBottom    = true;
  376.  
  377.         /* now create the Window */
  378.         if (windID > 0)
  379.         { // get from resource
  380.             aWindow = GetNewWindow(windID, p2wWPtr, (WindowPtr)NULL);
  381.             *anError = ResError();
  382.         }
  383.         else
  384.         { // Create from scratch, also moves/sizes appropriately
  385.             aWindow = NewWindow(p2wWPtr, windBoundsPtr, windTitle, windIsVisible, documentProc,
  386.                                 (WindowPtr)NULL, false/*hasGoAway*/, 0/*refcon*/);
  387.             *anError = MemError();
  388.         }
  389.     }
  390.  
  391.     /* Move the window to user-specified position? */
  392.     /* Do this only if getting from resources - already done (above) otherwise */
  393.     if (windID > 0)
  394.     {
  395.         if ((!*anError) && (windBoundsPtr != NULL))
  396.         {
  397.             MoveWindow(aWindow, (*windBoundsPtr).left, (*windBoundsPtr).top, false);
  398.             SizeWindow(aWindow, GET_RECT_WIDTH(*windBoundsPtr), GET_RECT_HEIGHT(*windBoundsPtr), false);
  399.         }
  400.     }
  401.  
  402.     if (!*anError)
  403.     {
  404.         // now its OK to call CloseWindow later..
  405.         p2wWPtr->p2wOpenedOK = true;
  406.  
  407.         SetPort(aWindow);
  408.  
  409.         /* Set its title to what the user passed in, if non-null */
  410.         /* Do this only if getting from resources - already done (above) otherwise */
  411.         if (windID > 0)
  412.             if (windTitle)                            // not a NULL pointer?
  413.                 if (*windTitle)                        // not an empty string?
  414.                     SetWTitle(aWindow, windTitle);    // then do it!
  415.  
  416.         /* set up the font in the port */
  417.         p2w_SetTextFont(p2wWPtr, windFont, windFontSize);
  418.  
  419.         /* set up the EditText buffer & area */
  420.         p2wi_GetTERect(p2wWPtr, &viewRect);
  421.         destRect = viewRect;
  422.         destRect.right = destRect.left + p2wWPtr->p2wMaxDocWidth;
  423.         p2wWPtr->p2wTEHandle = TENew(&destRect, &viewRect);
  424.         *anError = MemError();
  425.     }
  426.  
  427.     if (!*anError)
  428.     {
  429.         p2wi_AdjustViewRect(p2wWPtr->p2wTEHandle);
  430.         // turn on auto-scrolling
  431. //        TEAutoView(true, p2wWPtr->p2wTEHandle); -- later, when we auto-connect to scrollbars
  432.     }
  433.  
  434.     /* Create vertical scrollbar */
  435.     if (!*anError)
  436.     {
  437. #if defined(USE_P2W_RESOURCES)
  438.         p2wWPtr->p2wVScroller = GetNewControl(kp2w_VScrollID, aWindow);
  439.         *anError = ResError();
  440. #else
  441.         p2wWPtr->p2wVScroller = NewControl(aWindow, &(*aWindow).portRect, "\pp2w_Vert", false, 0, 0, 1, scrollBarProc, 0);
  442.         *anError = MemError();
  443. #endif // USE_P2W_RESOURCES
  444.         // Our window comes up in back, so turn OFF visibility of scrollbar initially
  445.         if (!*anError)
  446.             HideControl(p2wWPtr->p2wVScroller);
  447.     }
  448.  
  449.     /* Create horizontal scrollbar */
  450.     if (!*anError)
  451.     {
  452. #if defined(USE_P2W_RESOURCES)
  453.         p2wWPtr->p2wHScroller = GetNewControl(kp2w_HScrollID, aWindow);
  454.         *anError = ResError();
  455. #else
  456.         p2wWPtr->p2wHScroller = NewControl(aWindow, &(*aWindow).portRect, "\pp2w_Horz", false, 0, 0, 1, scrollBarProc, 0);
  457.         *anError = MemError();
  458. #endif // USE_P2W_RESOURCES
  459.         // Our window comes up in back, so turn OFF visibility of scrollbar initially
  460.         if (!*anError)
  461.             HideControl(p2wWPtr->p2wHScroller);
  462.     }
  463.  
  464.     // adjust & draw the controls, draw the window
  465.     if (!*anError)
  466.     {
  467.         p2wi_AdjustScrollbars(p2wWPtr, true/*kResize*/);
  468.         if (windIsVisible)
  469.             ShowWindow(aWindow);
  470.     }
  471.  
  472.     // Return to port after storm
  473.     SetPort(savedPort);    // I'm back..
  474.  
  475.     // close & dispose if any errors happened!
  476.     if (*anError)
  477.     {
  478.         p2w_DisposeWindow(p2wWPtr);
  479.         // if errors happened, don't give user any pointers
  480.         p2wWPtr = NULL;
  481.     }
  482.  
  483.     // remember this for the StdIO routines later..
  484.     local_p2wWindow = p2wWPtr;
  485.  
  486.     return (p2wWPtr);
  487.  
  488. } // p2w_NewWindow
  489.  
  490.  
  491.  
  492. /*
  493. ******************************************************************************
  494. Name:
  495.     p2w_DisposeWindow
  496. ------------------------------------------------------------------------------
  497. Purpose:
  498.     Deletes an existing p2w window structure and its related TE danglies.
  499. ------------------------------------------------------------------------------
  500. Description:
  501.     Disposes of the TE record, closes the window/grafport, and disposes
  502.     of the window/grafport itself.
  503. ------------------------------------------------------------------------------
  504. Parameters:
  505.     the_p2wPtr        The p2w window to dispose.
  506. ------------------------------------------------------------------------------
  507. When Used:
  508.     Called when a p2w window is no longer needed.
  509. ******************************************************************************
  510. */
  511. void p2w_DisposeWindow(p2w_WindowPtr_t the_p2wPtr)
  512. {
  513.     // Is the window pointer not null?
  514.     if (the_p2wPtr)
  515.         // is this really one of our p2w windows?
  516.         // (We don't want to dispose extra stuff if it's really
  517.         // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  518.         if (IS_P2W_WINDOW(the_p2wPtr))
  519.         {
  520.             // Dispose Window/GrafPort danglies if opened ok
  521.             if (the_p2wPtr->p2wOpenedOK)
  522.                 CloseWindow((WindowPtr)the_p2wPtr);
  523.             // Dispose of our TE Record
  524.             if (the_p2wPtr->p2wTEHandle)
  525.                 TEDispose(the_p2wPtr->p2wTEHandle);
  526.             // set fields back to nil, to help catch anyone touching them after dispose!
  527.             the_p2wPtr->p2wOpenedOK        = false;
  528.             the_p2wPtr->p2wTEHandle        = NULL;
  529.             the_p2wPtr->p2wVScroller    = NULL;
  530.             the_p2wPtr->p2wHScroller    = NULL;
  531.             the_p2wPtr->p2wClickHandler    = NULL;
  532.             // Dispose our version of window record itself now
  533.             DisposePtr((Ptr)the_p2wPtr);
  534.             local_p2wWindow = NULL;
  535.         }
  536. } // p2w_DisposeWindow
  537.  
  538.  
  539. /*
  540. ******************************************************************************
  541. Name:
  542.     p2w_SetTextFont
  543. ------------------------------------------------------------------------------
  544. Purpose:
  545.     Changes the Font Type and Size in the p2w window.
  546. ------------------------------------------------------------------------------
  547. Description:
  548. ------------------------------------------------------------------------------
  549. Parameters:
  550.     the_p2wPtr        The p2w window to update.
  551.     newFontType        The Font type to change to (monaco, courier, times, etc.)
  552.     newFontSize        The Font type to change to (9,10,12,etc.)
  553. ------------------------------------------------------------------------------
  554. When Used:
  555.     Called when text is to be added to the p2w window.
  556. ******************************************************************************
  557. */
  558. void p2w_SetTextFont
  559.                     (        p2w_WindowPtr_t        the_p2wPtr,
  560.                             short                newFontType,
  561.                             short                newFontSize)
  562. {
  563.     // is this really one of our p2w windows?
  564.     // (We don't want to fiddle with extra stuff if it's really
  565.     // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  566.     if (IS_P2W_WINDOW(the_p2wPtr))
  567.     {
  568.         // Tell our grafport that we have a new font
  569.         SetPort((GrafPtr)the_p2wPtr);
  570.         TextFont(newFontType);
  571.         TextSize(newFontSize);
  572.  
  573.         // Tell our TextEdit record that we have a new font..
  574.         if (the_p2wPtr->p2wTEHandle != NULL)
  575.         {    // TE Record is valid
  576.             (**the_p2wPtr->p2wTEHandle).txFont = newFontType;
  577.             (**the_p2wPtr->p2wTEHandle).txSize = newFontSize;
  578.             // let the TE adjust to this new font!
  579.             TECalText(the_p2wPtr->p2wTEHandle);
  580.             TEUpdate(&the_p2wPtr->p2wWindowRec.port.portRect,the_p2wPtr->p2wTEHandle);
  581.         }
  582.     }
  583. } // p2w_SetTextFont
  584.  
  585.  
  586. /*
  587. ******************************************************************************
  588. Name:
  589.     p2w_AddCString
  590. ------------------------------------------------------------------------------
  591. Purpose:
  592.     Adds the text in the C-style string passed to the p2w window.
  593. ------------------------------------------------------------------------------
  594. Description:
  595. ------------------------------------------------------------------------------
  596. Parameters:
  597.     the_p2wPtr        The p2w window to add to.
  598.     theCStrPtr        The string of text to add.
  599.     p2w_AddCString    function returns zero if ok, or an error #.
  600. ------------------------------------------------------------------------------
  601. When Used:
  602.     Called when text is to be added to the p2w window.
  603. ******************************************************************************
  604. */
  605. OSErr p2w_AddCString(p2w_WindowPtr_t the_p2wPtr, const char * theCStrPtr)
  606. {
  607.     OSErr    anError = noErr;
  608.     long    theStrLen;
  609.  
  610.     if (the_p2wPtr && theCStrPtr)        // if window and string ptrs are valid
  611.         // is this really one of our p2w windows?
  612.         // (We don't want to fiddle with extra stuff if it's really
  613.         // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  614.         if (IS_P2W_WINDOW(the_p2wPtr))
  615.             if (the_p2wPtr->p2wTEHandle)
  616.             {    // TE Record is valid
  617.                 theStrLen = strlen(theCStrPtr);
  618.                 if (theStrLen > 0)    // if string is not empty, add it
  619.                 {
  620.                     // If TE is too full, need to delete some at beginning before adding
  621.                     // (this looks weird, but it is the Mathematically Correct way to
  622.                     // compare numbers close to the edge of 32767-land.. note that
  623.                     // teLength+theStrLen could overflow, so we subtract instead.)
  624.                     if ((**(the_p2wPtr->p2wTEHandle)).teLength > (kMaxTELength - theStrLen))
  625.                     {
  626.                         // Delete some text at beginning of TE
  627.                         TESetSelect(0, theStrLen+kTEDeleteChunkSize, the_p2wPtr->p2wTEHandle);
  628.                         TEDelete(the_p2wPtr->p2wTEHandle);
  629.                     }
  630.                     // go to very end of TE (-1 is really +65535 in TE Worlds!)
  631.                     TESetSelect(-1, -1, the_p2wPtr->p2wTEHandle);
  632.                     // stick it in there
  633.                     TEInsert(theCStrPtr, theStrLen, the_p2wPtr->p2wTEHandle);
  634.                     // re-draw the scrollbars, since they may have changed
  635.                     p2wi_AdjustScrollbars(the_p2wPtr, false);
  636.                 }    // theStrLen > 0
  637.             }    // TE Record is valid
  638.     return(anError);
  639. } // p2w_AddCString
  640.  
  641.  
  642. /*
  643. ******************************************************************************
  644. Name:
  645.     p2w_DrawWindow
  646. ------------------------------------------------------------------------------
  647. Purpose:
  648.     Draw the contents of an application window.
  649. ------------------------------------------------------------------------------
  650. Description:
  651.     
  652. ------------------------------------------------------------------------------
  653. Parameters:
  654.     
  655. ------------------------------------------------------------------------------
  656. When Used:
  657.     
  658. ******************************************************************************
  659. */
  660. void p2w_DrawWindow(const p2w_WindowPtr_t the_p2wPtr)
  661. {
  662.     // is this really one of our p2w windows?
  663.     // (We don't want to dispose extra stuff if it's really
  664.     // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  665.     if (IS_P2W_WINDOW(the_p2wPtr))
  666.     {
  667.         // move in for the kill
  668.         SetPort((WindowPtr)the_p2wPtr);
  669.         // kill off old bits
  670.         EraseRect(&((WindowPtr)the_p2wPtr)->portRect);
  671.         // regain controls
  672.         DrawGrowIcon((WindowPtr)the_p2wPtr);
  673.         DrawControls((WindowPtr)the_p2wPtr);
  674.         // show them our text
  675.         TEUpdate(&((WindowPtr)the_p2wPtr)->portRect, the_p2wPtr->p2wTEHandle);
  676.     }
  677. } // p2w_DrawWindow
  678.  
  679.  
  680.  
  681. /*
  682. ******************************************************************************
  683. Name:
  684.     p2w_DoUpdate
  685. ------------------------------------------------------------------------------
  686. Purpose:
  687.     Update (redraw) the contents of an application window.
  688. ------------------------------------------------------------------------------
  689. Description:
  690.     
  691. ------------------------------------------------------------------------------
  692. Parameters:
  693.     
  694. ------------------------------------------------------------------------------
  695. When Used:
  696.     
  697. ******************************************************************************
  698. */
  699. void p2w_DoUpdate(const p2w_WindowPtr_t thep2wWindow)
  700. {
  701.     // move in for the kill
  702.     SetPort((WindowPtr)thep2wWindow);
  703.     BeginUpdate((WindowPtr)thep2wWindow);                /* this sets up the visRgn */
  704.     if (!EmptyRgn(((WindowPtr)thep2wWindow)->visRgn))    /* draw if updating needs to be done */
  705.         p2w_DrawWindow(thep2wWindow);
  706.     EndUpdate((WindowPtr)thep2wWindow);
  707. } // p2w_DoUpdate
  708.  
  709.  
  710. /*
  711. ******************************************************************************
  712. Name:
  713.     p2w_DoActivate
  714. ------------------------------------------------------------------------------
  715. Purpose:
  716.     This is called when a window is activated or deactivated.
  717.     It calls TextEdit to handle the selection.
  718. ------------------------------------------------------------------------------
  719. Description:
  720.     
  721. ------------------------------------------------------------------------------
  722. Parameters:
  723.     
  724. ------------------------------------------------------------------------------
  725. When Used:
  726.     
  727. ******************************************************************************
  728. */
  729. void p2w_DoActivate(const p2w_WindowPtr_t thep2wWindow, Boolean becomingActive)
  730. {
  731.     RgnHandle    tempRgn, clipRgn;
  732.  
  733.     // is this really one of our p2w windows?
  734.     // (We don't want to dispose extra stuff if it's really
  735.     // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  736.     if (IS_P2W_WINDOW(thep2wWindow))
  737.     {
  738.         /* move in for the kill */
  739.         SetPort((WindowPtr)thep2wWindow);
  740.  
  741.         /* force window to be redrawn on update */
  742.         InvalRect(&((WindowPtr)thep2wWindow)->portRect);
  743.  
  744.         if (becomingActive)
  745.         {
  746.             /*
  747.             Since we don’t want TEActivate to draw a selection
  748.             in an area where we’re going to erase and redraw,
  749.             we’ll clip out the update region before calling it.
  750.             */
  751.             tempRgn = NewRgn();
  752.             clipRgn = NewRgn();
  753.             if (tempRgn && clipRgn)
  754.             {
  755.                 p2wi_GetLocalUpdateRegion(thep2wWindow, tempRgn);    /* get localized update region */
  756.                 GetClip(clipRgn);
  757.                 DiffRgn(clipRgn, tempRgn, tempRgn);        /* subtract updateRgn from clipRgn */
  758.                 SetClip(tempRgn);
  759.                 TEActivate(thep2wWindow->p2wTEHandle);
  760.                 SetClip(clipRgn);                        /* restore the full-blown clipRgn */
  761.                 DisposeRgn(tempRgn);
  762.                 DisposeRgn(clipRgn);
  763.             }
  764.     
  765.             /* the controls must be redrawn on activation */
  766.             ShowControl(thep2wWindow->p2wVScroller);
  767.             ShowControl(thep2wWindow->p2wHScroller);
  768.         }
  769.         else
  770.         {    /* De-Activating.. */
  771.             TEDeactivate(thep2wWindow->p2wTEHandle);
  772.     
  773.             /* the controls must be hidden on deactivation */
  774.             HideControl(thep2wWindow->p2wVScroller);
  775.             HideControl(thep2wWindow->p2wHScroller);
  776.  
  777.             /* the growbox should be changed immediately here */
  778.             DrawGrowIcon((WindowPtr)thep2wWindow);
  779.     
  780.         }
  781.     }
  782. } // p2w_DoActivate
  783.  
  784.  
  785. /*
  786. ******************************************************************************
  787. Name:
  788.     p2w_DoGrow
  789. ------------------------------------------------------------------------------
  790. Purpose:
  791.     Called when a mouseDown occurs in the grow box of an active
  792.     window. In order to eliminate any 'flicker', we want to
  793.     invalidate only what is necessary. Since p2w_ResizeWindow
  794.     invalidates the whole portRect, we save the old TE
  795.     viewRect, intersect it with the new TE viewRect, and remove
  796.     the result from the update region. However, we must make
  797.     sure that any old update region that might have been around
  798.     gets put back. 
  799. ------------------------------------------------------------------------------
  800. Description:
  801.     
  802. ------------------------------------------------------------------------------
  803. Parameters:
  804.     
  805. ------------------------------------------------------------------------------
  806. When Used:
  807.     
  808. ******************************************************************************
  809. */
  810. void p2w_DoGrow(const p2w_WindowPtr_t thep2wWindow, EventRecord *theEvent)
  811. {
  812.     long        growResult;
  813.     Rect        tempRect;
  814. //    RgnHandle    tempRgn;
  815.     
  816.     // is this really one of our p2w windows?
  817.     // (We don't want to dispose extra stuff if it's really
  818.     // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  819.     if (IS_P2W_WINDOW(thep2wWindow))
  820.     {
  821.         // move in for the kill
  822.         SetPort((WindowPtr)thep2wWindow);
  823.     
  824.         /* set up limiting values */
  825.         GetMaxGrowRect((WindowPtr)thep2wWindow, &tempRect);    
  826.         tempRect.left = kMinDocSize;
  827.         tempRect.top = kMinDocSize;
  828.     
  829.         growResult = GrowWindow((WindowPtr)thep2wWindow, theEvent->where, &tempRect);
  830.         /* see if it really changed size */
  831.         if (growResult != 0)
  832.         {
  833. //            tempRect = (**thep2wWindow->p2wTEHandle).viewRect;    /* save old text box */
  834. //            tempRgn = NewRgn();
  835. //            p2wi_GetLocalUpdateRegion(thep2wWindow, tempRgn);        /* get localized update region */
  836.             SizeWindow((WindowPtr)thep2wWindow, GET_LOWORD(growResult), GET_HIWORD(growResult), true);
  837.             p2wi_ResizeWindow(thep2wWindow);
  838.     
  839.             /* calculate & validate the region that hasn’t changed, so it won’t get redrawn */
  840. //            SectRect(&tempRect, &(**thep2wWindow->p2wTEHandle).viewRect, &tempRect);
  841. //            ValidRect(&tempRect);                            /* take it out of update */
  842. //            InvalRgn(tempRgn);                                /* put back any prior update */
  843. //            DisposeRgn(tempRgn);
  844.         }
  845.     }
  846. } // p2w_DoGrow
  847.  
  848.  
  849. /*
  850. ******************************************************************************
  851. Name:
  852.     p2w_DoZoom
  853. ------------------------------------------------------------------------------
  854. Purpose:
  855.     Called when a mouseClick occurs in the zoom box of an active
  856.     window. Everything has to get re-drawn here, so we don't mind
  857.     that p2w_ResizeWindow invalidates the whole portRect. 
  858. ------------------------------------------------------------------------------
  859. Description:
  860.     
  861. ------------------------------------------------------------------------------
  862. Parameters:
  863.     
  864. ------------------------------------------------------------------------------
  865. When Used:
  866.     
  867. ******************************************************************************
  868. */
  869. void p2w_DoZoom(const p2w_WindowPtr_t thep2wWindow, short thePart)
  870. {
  871.     // is this really one of our p2w windows?
  872.     // (We don't want to dispose extra stuff if it's really
  873.     // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  874.     if (IS_P2W_WINDOW(thep2wWindow))
  875.     {
  876.         // move in for the kill
  877.         SetPort((WindowPtr)thep2wWindow);
  878.         EraseRect(&((WindowPtr)thep2wWindow)->portRect);
  879.         ZoomWindow((WindowPtr)thep2wWindow, thePart, (WindowPtr)thep2wWindow==FrontWindow());
  880.         p2wi_ResizeWindow(thep2wWindow);
  881.     }
  882. } // p2w_DoZoom
  883.  
  884.  
  885. /*
  886. ******************************************************************************
  887. Name:
  888.     p2w_SelectAll
  889. ------------------------------------------------------------------------------
  890. Purpose:
  891.     This will select the entire contents of a window.
  892. ------------------------------------------------------------------------------
  893. Description:
  894.     
  895. ------------------------------------------------------------------------------
  896. Parameters:
  897.     
  898. ------------------------------------------------------------------------------
  899. When Used:
  900.     
  901. ******************************************************************************
  902. */
  903. void p2w_SelectAll(const p2w_WindowPtr_t thep2wWindow)
  904. {
  905.     // is this really one of our p2w windows?
  906.     // (We don't want to dispose extra stuff if it's really
  907.     // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  908.     if (IS_P2W_WINDOW(thep2wWindow))
  909.     {
  910.         TESetSelect(0, -1, thep2wWindow->p2wTEHandle);
  911.     }
  912. } // p2w_SelectAll
  913.  
  914. /*
  915. ******************************************************************************
  916. Name:
  917.     p2w_DoContentClick
  918. ------------------------------------------------------------------------------
  919. Purpose:
  920.     This is called when a mouseDown occurs in the content of a window.
  921. ------------------------------------------------------------------------------
  922. Description:
  923.     
  924. ------------------------------------------------------------------------------
  925. Parameters:
  926.     
  927. ------------------------------------------------------------------------------
  928. When Used:
  929.     
  930. ******************************************************************************
  931. */
  932. void p2w_DoContentClick(const p2w_WindowPtr_t thep2wWindow, EventRecord *theEvent)
  933. {
  934.     Point        mouse;
  935.     ControlHandle control;
  936.     short        part, value;
  937.     Boolean        shiftDown;
  938.     Rect        teRect;
  939.  
  940.     // is this really one of our p2w windows?
  941.     // (We don't want to dispose extra stuff if it's really
  942.     // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr_t!)
  943.     if (IS_P2W_WINDOW(thep2wWindow))
  944.     {
  945.         SetPort((WindowPtr)thep2wWindow);
  946.     
  947.         /* get the click position */
  948.         mouse = theEvent->where;
  949.         GlobalToLocal(&mouse);
  950.     
  951.         /* see if we are in the viewRect. if so, we won’t check the controls */
  952.         p2wi_GetTERect(thep2wWindow, &teRect);
  953.         if (PtInRect(mouse, &teRect))
  954.         {
  955.             /* see if we need to extend the selection */
  956.             shiftDown = (theEvent->modifiers & shiftKey) != 0;    /* extend if Shift is down */
  957.             TEClick(mouse, shiftDown, thep2wWindow->p2wTEHandle);
  958.         }
  959.         else
  960.         {
  961.             part = FindControl(mouse, (WindowPtr)thep2wWindow, &control);
  962.             switch (part)
  963.             {
  964.                 case 0:        /* do nothing.. */
  965.                     break;
  966.                 case inThumb:
  967.                     value = GetCtlValue(control);
  968.                     part = TrackControl(control, mouse, nil);
  969.                     if (part != 0)
  970.                     {
  971.                         value -= GetCtlValue(control);
  972.                         /* value now has CHANGE in value; if value changed, scroll */
  973.                         if (value != 0)
  974.                             if (control == thep2wWindow->p2wVScroller)
  975.                                 TEScroll(0, value * (*thep2wWindow->p2wTEHandle)->lineHeight, thep2wWindow->p2wTEHandle);
  976.                             else
  977.                                 TEScroll(value, 0, thep2wWindow->p2wTEHandle);
  978.                     }
  979.                     break;
  980.                 default:    /* they clicked in an arrow, so track & scroll */
  981.                     if (control == thep2wWindow->p2wVScroller)
  982.                     {
  983. #if defined(__powerc)
  984.                         value = TrackControl(control, mouse, (ControlActionUPP) &gVScrollRD);
  985. #else
  986.                         value = TrackControl(control, mouse, (ProcPtr) p2wi_VScrollActionProc);
  987. #endif
  988.                     }
  989.                     else
  990.                     if (control == thep2wWindow->p2wHScroller)
  991.                     {
  992. #if defined(__powerc)
  993.                         value = TrackControl(control, mouse, (ControlActionUPP) &gHScrollRD);
  994. #else
  995.                         value = TrackControl(control, mouse, (ProcPtr) p2wi_HScrollActionProc);
  996. #endif
  997.                     }
  998.                     break;
  999.             }
  1000.         }
  1001.     }
  1002. } // p2w_DoContentClick
  1003.  
  1004.  
  1005.  
  1006. /*---------------------------------------------------------------------*/
  1007. /*==== Private internal p2w routines ====*/
  1008.     
  1009. /*
  1010. ******************************************************************************
  1011. Name:
  1012.     p2wi_GetTERect
  1013. ------------------------------------------------------------------------------
  1014. Purpose:
  1015.     Return a rectangle that is inset from the portRect by the
  1016.     size of the scrollbars, plus a bit.
  1017. ------------------------------------------------------------------------------
  1018. Description:
  1019.     
  1020. ------------------------------------------------------------------------------
  1021. Parameters:
  1022.     
  1023. ------------------------------------------------------------------------------
  1024. When Used:
  1025.     
  1026. ******************************************************************************
  1027. */
  1028. static void p2wi_GetTERect(const p2w_WindowPtr_t thep2wWindow, Rect *teRect)
  1029. {
  1030.     *teRect = ((WindowPtr)thep2wWindow)->portRect;
  1031.     InsetRect(teRect, kTextMargin, kTextMargin);    /* adjust for margin */
  1032.     teRect->bottom = teRect->bottom - 15;        /* and for the scrollbars */
  1033.     teRect->right = teRect->right - 15;
  1034. } // p2wi_GetTERect
  1035.  
  1036.  
  1037. /*
  1038. ******************************************************************************
  1039. Name:
  1040.     p2wi_AdjustTE
  1041. ------------------------------------------------------------------------------
  1042. Purpose:
  1043.     Scroll the TERec around to match up to the potentially updated scrollbar
  1044.     values. This is really useful when the window has been resized such that
  1045.     the scrollbars became inactive but the TERec was already scrolled.
  1046. ------------------------------------------------------------------------------
  1047. Description:
  1048.     
  1049. ------------------------------------------------------------------------------
  1050. Parameters:
  1051.     
  1052. ------------------------------------------------------------------------------
  1053. When Used:
  1054.     
  1055. ******************************************************************************
  1056. */
  1057. static void p2wi_AdjustTE(const p2w_WindowPtr_t thep2wWindow)
  1058. {
  1059.     short        hVal,vVal;
  1060.     TEPtr        te;
  1061.     
  1062.     vVal = GetCtlValue(thep2wWindow->p2wVScroller);
  1063.     hVal = GetCtlValue(thep2wWindow->p2wHScroller);
  1064.     te = *thep2wWindow->p2wTEHandle;
  1065.     TEScroll((te->viewRect.left - te->destRect.left) - hVal,
  1066.             (te->viewRect.top - te->destRect.top) - (vVal * te->lineHeight),
  1067.             thep2wWindow->p2wTEHandle);
  1068. } // p2wi_AdjustTE
  1069.  
  1070.  
  1071. /*
  1072. ******************************************************************************
  1073. Name:
  1074.     p2wi_AdjustViewRect
  1075. ------------------------------------------------------------------------------
  1076. Purpose:
  1077.     Update our TE view rect so it's the greatest multiple of
  1078.     the lineHeight that still fits in the old viewRect.
  1079. ------------------------------------------------------------------------------
  1080. Description:
  1081.     
  1082. ------------------------------------------------------------------------------
  1083. Parameters:
  1084.     
  1085. ------------------------------------------------------------------------------
  1086. When Used:
  1087.     
  1088. ******************************************************************************
  1089. */
  1090. static void p2wi_AdjustViewRect(TEHandle p2wTE)
  1091. {
  1092.     TEPtr        te;
  1093.     
  1094.     te = *p2wTE;
  1095.     te->viewRect.bottom = (((te->viewRect.bottom - te->viewRect.top) / te->lineHeight)
  1096.                             * te->lineHeight) + te->viewRect.top;
  1097. } // p2wi_AdjustViewRect
  1098.  
  1099.  
  1100. /*
  1101. ******************************************************************************
  1102. Name:
  1103.     p2wi_CommonAdjustScroller
  1104. ------------------------------------------------------------------------------
  1105. Purpose:
  1106.     Calculate the new control maximum value and current value,
  1107.     for the horizontal or vertical scrollbar. The vertical max
  1108.     is calculated by comparing the number of lines to the
  1109.     vertical size of the viewRect. The horizontal max is
  1110.     calculated by comparing the maximum document width to the
  1111.     width of the viewRect. The current values are set by
  1112.     comparing the offset between the view and destination
  1113.     rects. If necessary and we canRedraw, have the control be
  1114.     re-drawn by calling ShowControl. 
  1115. ------------------------------------------------------------------------------
  1116. Description:
  1117.     
  1118. ------------------------------------------------------------------------------
  1119. Parameters:
  1120.     
  1121. ------------------------------------------------------------------------------
  1122. When Used:
  1123.     Called by p2wi_AdjustScrollValues, twice.
  1124. ******************************************************************************
  1125. */
  1126. static void p2wi_CommonAdjustScroller(const Boolean isVert, const p2w_WindowPtr_t thep2wWindow, ControlHandle control, TEHandle theTEHandle, const Boolean canRedraw)
  1127. {
  1128.     short        value, lines, max;
  1129.     short        oldValue, oldMax;
  1130.     
  1131.     oldValue = GetCtlValue(control);
  1132.     oldMax = GetCtlMax(control);
  1133.     if (isVert)
  1134.     {
  1135.         lines = (**theTEHandle).nLines;
  1136.         /* since nLines isn’t right if the last character is a return, check for that case */
  1137.         if ( *(*(**theTEHandle).hText + (**theTEHandle).teLength - 1) == '\n')
  1138.             lines += 1;
  1139.         max = lines
  1140.             -    (
  1141.                 ((**theTEHandle).viewRect.bottom - (**theTEHandle).viewRect.top)
  1142.                 / (**theTEHandle).lineHeight
  1143.                 );
  1144.     }
  1145.     else
  1146.         max = thep2wWindow->p2wMaxDocWidth
  1147.             -    (
  1148.                 (**theTEHandle).viewRect.right - (**theTEHandle).viewRect.left
  1149.                 );
  1150.     
  1151.     if (max < 0)
  1152.         max = 0;
  1153.     SetCtlMax(control, max);
  1154.     
  1155.     if (isVert)
  1156.     {
  1157.         // always scroll to end?
  1158.         if (thep2wWindow->p2wAlwaysScrollToBottom)
  1159.             value = max;
  1160.         else
  1161.             value = ((**theTEHandle).viewRect.top - (**theTEHandle).destRect.top)
  1162.                     / (**theTEHandle).lineHeight;
  1163.     }
  1164.     else
  1165.         value = (**theTEHandle).viewRect.left - (**theTEHandle).destRect.left;
  1166.     
  1167.     if ( value < 0 )
  1168.         value = 0;
  1169.     else
  1170.         if (value >  max)
  1171.             value = max;
  1172.     
  1173.     SetCtlValue(control, value);
  1174.  
  1175.     /* now redraw the control if it needs to be and can be */
  1176.     if (canRedraw || (max != oldMax) || (value != oldValue))
  1177.     {
  1178.         ShowControl(control);
  1179. //        Draw1Control(control);
  1180.     }
  1181. } // p2wi_CommonAdjustScroller
  1182.  
  1183.  
  1184. /*
  1185. ******************************************************************************
  1186. Name:
  1187.     p2wi_AdjustScrollValues
  1188. ------------------------------------------------------------------------------
  1189. Purpose:
  1190.     Simply call the common adjust routine for both the vertical
  1191.     and horizontal scrollbars.
  1192. ------------------------------------------------------------------------------
  1193. Description:
  1194.     
  1195. ------------------------------------------------------------------------------
  1196. Parameters:
  1197.     
  1198. ------------------------------------------------------------------------------
  1199. When Used:
  1200.     
  1201. ******************************************************************************
  1202. */
  1203. static void p2wi_AdjustScrollValues(const p2w_WindowPtr_t thep2wWindow, const Boolean doRedraw)
  1204. {
  1205.     p2wi_CommonAdjustScroller(true, thep2wWindow, thep2wWindow->p2wVScroller, thep2wWindow->p2wTEHandle, doRedraw);
  1206.     p2wi_CommonAdjustScroller(false, thep2wWindow, thep2wWindow->p2wHScroller, thep2wWindow->p2wTEHandle, doRedraw);
  1207. } // p2wi_AdjustScrollValues
  1208.  
  1209.  
  1210.  
  1211. /*
  1212. ******************************************************************************
  1213. Name:
  1214.     p2wi_AdjustScrollSizes
  1215. ------------------------------------------------------------------------------
  1216. Purpose:
  1217.     Re-calculate the position and size of the viewRect and the
  1218.     scrollbars. The constant kScrollTweek compensates for the
  1219.     "off-by-one" requirements of the scrollbars that need their
  1220.     borders coinciding with the growbox. 
  1221. ------------------------------------------------------------------------------
  1222. Description:
  1223.     
  1224. ------------------------------------------------------------------------------
  1225. Parameters:
  1226.     
  1227. ------------------------------------------------------------------------------
  1228. When Used:
  1229.     
  1230. ******************************************************************************
  1231. */
  1232. static void p2wi_AdjustScrollSizes(const p2w_WindowPtr_t thep2wWindow)
  1233. {
  1234.     Rect        teRect;
  1235.  
  1236.     p2wi_GetTERect(thep2wWindow, &teRect);    // start with TERect..
  1237.     (*thep2wWindow->p2wTEHandle)->viewRect = teRect;
  1238.     p2wi_AdjustViewRect(thep2wWindow->p2wTEHandle);    /* snap to nearest line */
  1239.  
  1240.     /* Vertical */
  1241.     MoveControl(thep2wWindow->p2wVScroller,
  1242.                 ((WindowPtr)thep2wWindow)->portRect.right - kScrollbarAdjust,
  1243.                 -1);
  1244.     SizeControl(thep2wWindow->p2wVScroller,
  1245.                 kScrollbarWidth,
  1246.                 (((WindowPtr)thep2wWindow)->portRect.bottom
  1247.                     - ((WindowPtr)thep2wWindow)->portRect.top)
  1248.                     - (kScrollbarAdjust - kScrollTweek));
  1249.  
  1250.     /* Horizontal */
  1251.     MoveControl(thep2wWindow->p2wHScroller,
  1252.                 -1,
  1253.                 ((WindowPtr)thep2wWindow)->portRect.bottom - kScrollbarAdjust);
  1254.     SizeControl(thep2wWindow->p2wHScroller,
  1255.                 (((WindowPtr)thep2wWindow)->portRect.right
  1256.                     - ((WindowPtr)thep2wWindow)->portRect.left)
  1257.                     - (kScrollbarAdjust - kScrollTweek),
  1258.                 kScrollbarWidth);
  1259. } // p2wi_AdjustScrollSizes
  1260.  
  1261.  
  1262. /*
  1263. ******************************************************************************
  1264. Name:
  1265.     p2wi_AdjustScrollbars
  1266. ------------------------------------------------------------------------------
  1267. Purpose:
  1268.     Recalculate the scrollbar pos/values, and redraw if need be.
  1269. ------------------------------------------------------------------------------
  1270. Description:
  1271.     Turn off the controls by jamming a zero into their contrlVis fields
  1272.     (HideControl erases them and we don't want that). If the controls
  1273.     are to be resized as well, call the procedure to do that, then call
  1274.     the procedure to adjust the maximum and current values. Finally,
  1275.     re-enable the controls by jamming a $FF in their contrlVis fields.  
  1276. ------------------------------------------------------------------------------
  1277. Parameters:
  1278.     
  1279. ------------------------------------------------------------------------------
  1280. When Used:
  1281.     
  1282. ******************************************************************************
  1283. */
  1284. static void p2wi_AdjustScrollbars(const p2w_WindowPtr_t thep2wWindow, const Boolean doResize)
  1285. {
  1286.     short    oldHvis, oldVvis;
  1287.  
  1288.     oldVvis = (**thep2wWindow->p2wVScroller).contrlVis;
  1289.     oldHvis = (**thep2wWindow->p2wHScroller).contrlVis;
  1290.  
  1291.     /* First, turn visibility of scrollbars off to eliminate unwanted redrawing */
  1292.     (*thep2wWindow->p2wVScroller)->contrlVis = kControlInvisible;    /* turn them off */
  1293.     (*thep2wWindow->p2wHScroller)->contrlVis = kControlInvisible;
  1294.  
  1295.     /* move & size as needed */
  1296.     if (doResize)
  1297.         p2wi_AdjustScrollSizes(thep2wWindow);
  1298.  
  1299.     /* adjust constrols' max and current values */
  1300.     p2wi_AdjustScrollValues(thep2wWindow, doResize);
  1301.  
  1302.     /* now scroll the TE record to match the scrollbars */
  1303.     p2wi_AdjustTE(thep2wWindow);
  1304.  
  1305.     /* Now, restore visibility in case we never had to ShowControl during adjustment */
  1306.     (*thep2wWindow->p2wVScroller)->contrlVis = oldVvis;    /* restore them */
  1307.     (*thep2wWindow->p2wHScroller)->contrlVis = oldHvis;
  1308. } // p2wi_AdjustScrollbars
  1309.  
  1310.  
  1311. /*
  1312. ******************************************************************************
  1313. Name:
  1314.     p2wi_ResizeWindow
  1315. ------------------------------------------------------------------------------
  1316. Purpose:
  1317.     Called when the window has been resized to fix up the controls and content.
  1318. ------------------------------------------------------------------------------
  1319. Description:
  1320.     
  1321. ------------------------------------------------------------------------------
  1322. Parameters:
  1323.     
  1324. ------------------------------------------------------------------------------
  1325. When Used:
  1326.     
  1327. ******************************************************************************
  1328. */
  1329. static void p2wi_ResizeWindow(const p2w_WindowPtr_t thep2wWindow)
  1330. {
  1331.     p2wi_AdjustScrollbars(thep2wWindow, true);
  1332.     InvalRect(&((WindowPtr)thep2wWindow)->portRect);
  1333. } // p2wi_ResizeWindow
  1334.  
  1335.  
  1336.  
  1337. /*
  1338. ******************************************************************************
  1339. Name:
  1340.     p2wi_GetLocalUpdateRegion
  1341. ------------------------------------------------------------------------------
  1342. Purpose:
  1343.     Returns the update region in local coordinates
  1344. ------------------------------------------------------------------------------
  1345. Description:
  1346.     
  1347. ------------------------------------------------------------------------------
  1348. Parameters:
  1349.     
  1350. ------------------------------------------------------------------------------
  1351. When Used:
  1352.     
  1353. ******************************************************************************
  1354. */
  1355. static void p2wi_GetLocalUpdateRegion(const p2w_WindowPtr_t thep2wWindow, RgnHandle localRgn)
  1356. {
  1357.     CopyRgn(((WindowPeek)thep2wWindow)->updateRgn, localRgn);    /* save old update region */
  1358.     OffsetRgn(localRgn, ((WindowPtr)thep2wWindow)->portBits.bounds.left,
  1359.                         ((WindowPtr)thep2wWindow)->portBits.bounds.top);
  1360. } // p2wi_GetLocalUpdateRegion
  1361.  
  1362.  
  1363.  
  1364. /*
  1365. ******************************************************************************
  1366. Name:
  1367.     p2wi_CommonScrollAction
  1368. ------------------------------------------------------------------------------
  1369. Purpose:
  1370.     Common algorithm for pinning the value of a control. It
  1371.     returns the actual amount the value of the control changed.
  1372.     Note the pinning is done for the sake of returning the
  1373.     amount the control value changed.
  1374. ------------------------------------------------------------------------------
  1375. Description:
  1376.     
  1377. ------------------------------------------------------------------------------
  1378. Parameters:
  1379.     
  1380. ------------------------------------------------------------------------------
  1381. When Used:
  1382.     Called by p2wi_HScrollActionProc, p2wi_VScrollActionProc
  1383. ******************************************************************************
  1384. */
  1385. static void p2wi_CommonScrollAction(ControlHandle control, short *amount)
  1386. {
  1387.     short        value, max;
  1388.     
  1389.     /* get the current value.. */
  1390.     value = GetCtlValue(control);
  1391.  
  1392.     /* and the biggest value */
  1393.     max = GetCtlMax(control);
  1394.  
  1395.     *amount = value - *amount;
  1396.     if ( *amount < 0 )
  1397.         *amount = 0;
  1398.     else if ( *amount > max )
  1399.         *amount = max;
  1400.     SetCtlValue(control, *amount);
  1401.  
  1402.     /* figure out the delta change */
  1403.     *amount = value - *amount;
  1404. } // p2wi_CommonScrollAction
  1405.  
  1406.  
  1407. /*
  1408. ******************************************************************************
  1409. Name:
  1410.     p2wi_VScrollActionProc
  1411. ------------------------------------------------------------------------------
  1412. Purpose:
  1413.     Determines how much to change the value of the vertical scrollbar by,
  1414.     and how much to scroll the TE record.
  1415. ------------------------------------------------------------------------------
  1416. Description:
  1417.     
  1418. ------------------------------------------------------------------------------
  1419. Parameters:
  1420.     
  1421. ------------------------------------------------------------------------------
  1422. When Used:
  1423.     Callback routine, called by toolbox
  1424. ******************************************************************************
  1425. */
  1426. pascal void p2wi_VScrollActionProc(ControlHandle control, short part)
  1427. {
  1428.     short            amount;
  1429.     p2w_WindowPtr_t    p2w_Window;
  1430.     TEPtr            te;
  1431.     
  1432.     if (part != 0)
  1433.     {    /* if it was actually in the control */
  1434.         p2w_Window = (p2w_WindowPtr_t)(*control)->contrlOwner;
  1435.         te = *p2w_Window->p2wTEHandle;
  1436.         switch (part)
  1437.         {
  1438.             case inUpButton:
  1439.             case inDownButton:        /* one line */
  1440.                 amount = 1;
  1441.                 break;
  1442.             case inPageUp:            /* one page */
  1443.             case inPageDown:
  1444.                 amount = (te->viewRect.bottom - te->viewRect.top) / te->lineHeight;
  1445.                 break;
  1446.         }
  1447.         if ((part == inDownButton) || (part == inPageDown))
  1448.             amount = -amount;        /* reverse direction if going down */
  1449.         p2wi_CommonScrollAction(control, &amount);
  1450.         if (amount != 0)
  1451.             TEScroll(0, amount * te->lineHeight, p2w_Window->p2wTEHandle);
  1452.     }
  1453. } // p2wi_VScrollActionProc
  1454.  
  1455.  
  1456. /*
  1457. ******************************************************************************
  1458. Name:
  1459.     p2wi_HScrollActionProc
  1460. ------------------------------------------------------------------------------
  1461. Purpose:
  1462.     Determines how much to change the value of the horizontal scrollbar by,
  1463.     and how much to scroll the TE record.
  1464. ------------------------------------------------------------------------------
  1465. Description:
  1466.     
  1467. ------------------------------------------------------------------------------
  1468. Parameters:
  1469.     
  1470. ------------------------------------------------------------------------------
  1471. When Used:
  1472.     Callback routine, called by toolbox
  1473. ******************************************************************************
  1474. */
  1475. pascal void p2wi_HScrollActionProc(ControlHandle control, short part)
  1476. {
  1477.     short            amount;
  1478.     p2w_WindowPtr_t    p2w_Window;
  1479.     TEPtr            te;
  1480.     
  1481.     if (part != 0)
  1482.     {    /* if it was actually in the control */
  1483.         p2w_Window = (p2w_WindowPtr_t)(*control)->contrlOwner;
  1484.         te = *p2w_Window->p2wTEHandle;
  1485.         switch (part)
  1486.         {
  1487.             case inUpButton:
  1488.             case inDownButton:        /* some pixels */
  1489.                 amount = kButtonScroll;
  1490.                 break;
  1491.             case inPageUp:            /* a whole page */
  1492.             case inPageDown:
  1493.                 amount = te->viewRect.right - te->viewRect.left;
  1494.                 break;
  1495.         }
  1496.         if ( (part == inDownButton) || (part == inPageDown) )
  1497.             amount = -amount;        /* reverse direction.. */
  1498.         p2wi_CommonScrollAction(control, &amount);
  1499.         if ( amount != 0 )
  1500.             TEScroll(amount, 0, p2w_Window->p2wTEHandle);
  1501.     }
  1502. } // p2wi_HScrollActionProc
  1503.  
  1504.  
  1505. /*---------------------------------------------------------------------*/
  1506. /*==== Standard C library fns ====*/
  1507.  
  1508. /*
  1509. ******************************************************************************
  1510. Name:
  1511.     p2wi_StdCOut_BottleNeck
  1512. ------------------------------------------------------------------------------
  1513. Purpose:
  1514.     Internal Standard C output replacement common bottleneck routine..
  1515.     This is what they all call to actually display the string/character.
  1516. ------------------------------------------------------------------------------
  1517. Description:
  1518.     
  1519. ------------------------------------------------------------------------------
  1520. Parameters:
  1521.     
  1522. ------------------------------------------------------------------------------
  1523. When Used:
  1524.     
  1525. ******************************************************************************
  1526. */
  1527. static int p2wi_StdCOut_BottleNeck(FILE *stream)
  1528. {
  1529.     int        x;
  1530.     char    *OutBuf, *outp;
  1531.  
  1532.     // get ahold of output buffer
  1533.     OutBuf = *p2w_Stdio_OutBuf_Hdl;
  1534.     // make sure the string at least stops here! (maybe check strlen first for overflow errors?)
  1535.     *(OutBuf+kMaxStdIOBuffSize-1) = '\0';
  1536.  
  1537.     // Replace any line feeds (0x0a) with Macintosh carriage returns (0x0d)
  1538.     // This is mainly for Think C compatibility, since Think faithfully
  1539.     // literally adopted the K&R C idea (from Unix) that '\n' is really 0x0a,
  1540.     // and Apple's MPW C bends '\n' to 0x0d for better file compatibility.
  1541.  
  1542. /* Note: For now, do this in both MPW and Think C.  This will FORCE the mapping
  1543. of any LFs to CRs.  The main reason for doing this is to catch the odd times
  1544. that the source code uses either '\r', or worse, '\0x0a' to embed returns! */
  1545. /*        if ('\n' != 0x0d) -- commented out to force issue, per above comment */
  1546.     {
  1547.         outp = OutBuf;
  1548.         while (*outp)
  1549.         {
  1550.             if (*outp == 0x0a)
  1551.               *outp = 0x0d;
  1552.             outp++;
  1553.         }
  1554.     }
  1555.  
  1556.     // If the output is for standard output (stderr/stdout) then capture it into our window,
  1557.     // else send it on to the standard C file output library routine.
  1558.     if ((stream == stderr) || (stream == stdout))
  1559.     {
  1560.         x = p2w_AddCString(local_p2wWindow, OutBuf);    // add it into window
  1561.     }
  1562.     else
  1563.     {
  1564.         // call a real std. C library routine.  This allows output to real
  1565.         // stdio C files to pass through unmolested.
  1566.         x = fwrite(OutBuf, strlen(OutBuf), 1, stream);
  1567.     }
  1568.  
  1569.     return x;
  1570.  
  1571. } // p2wi_StdCOut_BottleNeck
  1572.  
  1573.  
  1574. /*
  1575. ******************************************************************************
  1576. Name:
  1577.     p2wi_vfprintf
  1578. ------------------------------------------------------------------------------
  1579. Purpose:
  1580.     Internal common formatting handler for fprintf/printf
  1581. ------------------------------------------------------------------------------
  1582. Description:
  1583.     
  1584. ------------------------------------------------------------------------------
  1585. Parameters:
  1586.     
  1587. ------------------------------------------------------------------------------
  1588. When Used:
  1589.     
  1590. ******************************************************************************
  1591. */
  1592. static int p2wi_vfprintf(FILE *stream, const char *format, va_list va_args)
  1593. {
  1594.     int        x;
  1595.     char    *outBuf;
  1596.  
  1597.     // get ahold of output buffer
  1598.     HLock(p2w_Stdio_OutBuf_Hdl);
  1599.     outBuf = *p2w_Stdio_OutBuf_Hdl;
  1600.  
  1601. #if defined(NEEDS_DEBUG)
  1602. {
  1603.     // stick in a TE-length value debug into the TE record
  1604.     int daLen = (**(local_p2wWindow->p2wTEHandle)).teLength;
  1605.     sprintf(outBuf, "[%5d] ",daLen);
  1606.     x = p2wi_StdCOut_BottleNeck(stream);
  1607. }
  1608. #endif // NEEDS_DEBUG
  1609.  
  1610.     // use C library routine to do printf formatting of the string into buffer
  1611.     x = vsprintf(outBuf, format, va_args); // format it into a string
  1612.  
  1613.     // do the window output
  1614.     x = p2wi_StdCOut_BottleNeck(stream);
  1615.  
  1616.     // cut buffer adrift again..
  1617.     HUnlock(p2w_Stdio_OutBuf_Hdl);
  1618.  
  1619.     return x;
  1620. } // p2wi_vfprintf
  1621.  
  1622.  
  1623.  
  1624. int p2w_fflush(FILE *stream)
  1625. {
  1626. #pragma unused (stream)
  1627.     int        x;
  1628.  
  1629.     /* major no-op, dude */
  1630.     x = 0;
  1631.     return x;
  1632. } // p2w_fflush
  1633.  
  1634.  
  1635.  
  1636.  
  1637. int p2w_fprintf(FILE *stream, const char *format, ...)
  1638. {
  1639.     va_list    va_args;
  1640.     int        x;
  1641.  
  1642.     // use our bottleneck routine to do printf formatting
  1643.     va_start(va_args, format);
  1644.     x = p2wi_vfprintf(stream, format, va_args); // format it into a string
  1645.     va_end(va_args);
  1646.  
  1647.     return x;
  1648. } // p2w_fprintf
  1649.  
  1650.  
  1651. int p2w_fputc(int theChar, FILE *stream)
  1652. {
  1653.     int        x;
  1654.     char    *outBuf;
  1655.  
  1656.     // get ahold of output buffer & make char into string
  1657.     HLock(p2w_Stdio_OutBuf_Hdl);
  1658.     outBuf = *p2w_Stdio_OutBuf_Hdl;
  1659.  
  1660.     outBuf[0] = theChar;
  1661.     outBuf[1] = '\0';
  1662.  
  1663.     x = p2wi_StdCOut_BottleNeck(stream);
  1664.  
  1665.     HUnlock(p2w_Stdio_OutBuf_Hdl);
  1666.  
  1667.     return x;
  1668.  
  1669. } // p2w_fputc
  1670.  
  1671.  
  1672. int p2w_fputs(const char *theString, FILE *stream)
  1673. {
  1674.     int        x;
  1675.     char    *outBuf;
  1676.  
  1677.     // get ahold of output buffer
  1678.     HLock(p2w_Stdio_OutBuf_Hdl);
  1679.     outBuf = *p2w_Stdio_OutBuf_Hdl;
  1680.  
  1681.     // Copy string into buffer & write it
  1682.     BlockMove(theString, outBuf, kMaxStdIOBuffSize);
  1683.     x = p2wi_StdCOut_BottleNeck(stream);
  1684.  
  1685.     // "puts()" puts a newline afterwards..
  1686.     if ((stream == stderr) || (stream == stdout))
  1687.         p2w_putc('\n', stream);
  1688.  
  1689.     // cut buffer adrift again..
  1690.     HUnlock(p2w_Stdio_OutBuf_Hdl);
  1691.  
  1692.     return x;
  1693. } // p2w_fputs
  1694.  
  1695.  
  1696. int p2w_printf(const char * format, ...)
  1697. {
  1698.     va_list    va_args;
  1699.     int        x;
  1700.  
  1701.     // use our bottleneck routine to do printf formatting
  1702.     va_start(va_args, format);
  1703.     x = p2wi_vfprintf(stdout, format, va_args); // format it into a string
  1704.     va_end(va_args);
  1705.  
  1706.     return x;
  1707. } // p2w_printf
  1708.  
  1709.  
  1710. int p2w_putc(int theChar, FILE *stream)
  1711. {
  1712.     return p2w_fputc(theChar, stream);
  1713. } // p2w_putc
  1714.  
  1715.  
  1716. int p2w_putchar(const char theChar)
  1717. {
  1718.     return p2w_fputc(theChar, stdout);
  1719. } // p2w_putchar
  1720.  
  1721.  
  1722. int p2w_puts(const char *theString)
  1723. {
  1724.     return p2w_fputs(theString, stdout);
  1725. } // p2w_puts
  1726.